﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Motorway_Simulator.Components;

namespace Motorway_Simulator.FileIO
{

    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class SimObject
    {

         /// <summary>
        /// Holds south bound lanes
        /// </summary>
        private LinkedList<LinkedList<RoadUnit>> southBoundLanes;
        /// <summary>
        /// Holds north bound lanes
        /// </summary>
        private LinkedList<LinkedList<RoadUnit>> northBoundLanes;
        /// <summary>
        /// Holds east bound lanes
        /// </summary>
        private LinkedList<LinkedList<RoadUnit>> eastBoundLanes;
        /// <summary>
        /// Holds west bound lanes
        /// </summary>
        private LinkedList<LinkedList<RoadUnit>> westBoundLanes;



        /// <summary>
        /// Hold all the roadUnits
        /// </summary>
        private List<RoadUnit> roadUnits;

     

        public SimObject()
        {
            southBoundLanes = new LinkedList<LinkedList<RoadUnit>>();
            northBoundLanes = new LinkedList<LinkedList<RoadUnit>>();
            eastBoundLanes = new LinkedList<LinkedList<RoadUnit>>();
            westBoundLanes = new LinkedList<LinkedList<RoadUnit>>();
        }

        /// <summary>
        /// Algorithm which adds to linked list intelligently.
        /// </summary>
        /// <param name="roadUnit">The road unit.</param>
        public void AddToLinkedList(RoadUnit roadUnit)
        {
            switch (roadUnit.Direction1)
            {
                case RoadUnit.Direction.NORTH:
                    {

                        if (northBoundLanes.Count == 0)
                        {
                            LinkedList<RoadUnit> northBoundLane = new LinkedList<RoadUnit>();
                            northBoundLane.AddFirst(roadUnit);
                            northBoundLanes.AddFirst(northBoundLane);
                        }
                        else
                        {
                            LinkedList<RoadUnit> previous = null;
                            foreach (LinkedList<RoadUnit> northBoundLane in northBoundLanes)
                            {
                                if (northBoundLane.First.Value.Position.X == roadUnit.Position.X)
                                {
                                    northBoundLane.AddLast(roadUnit);
                                }

                                else if (northBoundLane.First.Value.Position.X > roadUnit.Position.X)
                                {
                                    LinkedList<RoadUnit> newNorthBoundLane = new LinkedList<RoadUnit>();
                                    newNorthBoundLane.AddFirst(roadUnit);
                                    if (previous == null)
                                    {
                                        northBoundLanes.AddFirst(northBoundLane);
                                    }
                                    else if (previous.First.Value.Position.X < roadUnit.Position.X)
                                    {
                                        northBoundLanes.AddBefore(northBoundLanes.Find(northBoundLane), newNorthBoundLane);
                                    }
                                }
                            }
                        }

                    }
                    break;

                case RoadUnit.Direction.SOUTH:
                    {
                        if (southBoundLanes.Count == 0)
                        {
                            LinkedList<RoadUnit> southBoundLane = new LinkedList<RoadUnit>();
                            southBoundLane.AddFirst(roadUnit);
                            southBoundLanes.AddFirst(southBoundLane);
                        }

                        else
                        {
                            LinkedList<RoadUnit> previous = null;
                            foreach (LinkedList<RoadUnit> southBoundLane in southBoundLanes)
                            {
                                if (southBoundLane.First.Value.Position.X == roadUnit.Position.X)
                                {
                                    southBoundLane.AddLast(roadUnit);
                                }

                                else if (southBoundLane.First.Value.Position.X > roadUnit.Position.X)
                                {
                                    LinkedList<RoadUnit> newSouthBoundLane = new LinkedList<RoadUnit>();
                                    newSouthBoundLane.AddFirst(roadUnit);
                                    if (previous == null)
                                    {
                                        southBoundLanes.AddFirst(southBoundLane);
                                    }
                                    else if (previous.First.Value.Position.X < roadUnit.Position.X)
                                    {
                                        southBoundLanes.AddBefore(southBoundLanes.Find(southBoundLane), newSouthBoundLane);
                                    }
                                }
                            }
                        }
                        break;
                    }

                case RoadUnit.Direction.EAST:
                    {
                        if (eastBoundLanes.Count == 0)
                        {
                            LinkedList<RoadUnit> eastBoundLane = new LinkedList<RoadUnit>();
                            eastBoundLane.AddFirst(roadUnit);
                            eastBoundLanes.AddFirst(eastBoundLane);
                        }
                        else
                        {
                            LinkedList<RoadUnit> previous = null;
                            foreach (LinkedList<RoadUnit> eastBoundLane in eastBoundLanes)
                            {
                                if (eastBoundLane.First.Value.Position.Y == roadUnit.Position.Y)
                                {
                                    eastBoundLane.AddLast(roadUnit);
                                }


                                else if (eastBoundLane.First.Value.Position.Y > roadUnit.Position.Y)
                                {
                                    LinkedList<RoadUnit> newEastBoundLane = new LinkedList<RoadUnit>();
                                    newEastBoundLane.AddFirst(roadUnit);
                                    if (previous == null)
                                    {
                                        eastBoundLanes.AddFirst(eastBoundLane);
                                    }
                                    else if (previous.First.Value.Position.Y < roadUnit.Position.Y)
                                    {
                                        eastBoundLanes.AddBefore(eastBoundLanes.Find(eastBoundLane), newEastBoundLane);
                                    }
                                }
                            }
                        }
                        break;
                    }
                case RoadUnit.Direction.WEST:
                    {
                        if (westBoundLanes.Count == 0)
                        {
                            LinkedList<RoadUnit> westBoundLane = new LinkedList<RoadUnit>();
                            westBoundLane.AddFirst(roadUnit);
                            westBoundLanes.AddFirst(westBoundLane);
                        }

                        else
                        {
                            LinkedList<RoadUnit> previous = null;
                            foreach (LinkedList<RoadUnit> westBoundLane in westBoundLanes)
                            {
                                if (westBoundLane.First.Value.Position.Y == roadUnit.Position.Y)
                                {
                                    westBoundLane.AddLast(roadUnit);
                                }

                                else if (westBoundLane.First.Value.Position.Y > roadUnit.Position.Y)
                                {
                                    LinkedList<RoadUnit> newWestBoundLane = new LinkedList<RoadUnit>();
                                    newWestBoundLane.AddFirst(roadUnit);
                                    if (previous == null)
                                    {
                                        westBoundLanes.AddFirst(westBoundLane);
                                    }
                                    else if (previous.First.Value.Position.Y < roadUnit.Position.Y)
                                    {
                                        westBoundLanes.AddBefore(westBoundLanes.Find(westBoundLane), newWestBoundLane);
                                    }
                                }
                            }
                        }
                    }
                    break;


                default:
                    throw new Exception("Erroer");

                    break;

            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SimObject"/> class.
        /// </summary>
        /// <param name="southBoundLanes">The south bound lanes.</param>
        /// <param name="northBoundLanes">The north bound lanes.</param>
        /// <param name="eastBoundLanes">The east bound lanes.</param>
        /// <param name="westBoundLanes">The west bound lanes.</param>
        public SimObject(LinkedList<LinkedList<RoadUnit>> southBoundLanes, LinkedList<LinkedList<RoadUnit>> northBoundLanes,
            LinkedList<LinkedList<RoadUnit>> eastBoundLanes, LinkedList<LinkedList<RoadUnit>> westBoundLanes, List<RoadUnit> roadUnits)
        {
            this.eastBoundLanes = eastBoundLanes;
            this.southBoundLanes = southBoundLanes;
            this.northBoundLanes = northBoundLanes;
            this.westBoundLanes = westBoundLanes;
            this.roadUnits = roadUnits;

        }


        /// <summary>
        /// Gets or sets the west bound lanes.
        /// </summary>
        /// <value>The west bound lanes.</value>
        public LinkedList<LinkedList<RoadUnit>> WestBoundLanes
        {
            get { return westBoundLanes; }
            set { westBoundLanes = value; }
        }

        /// <summary>
        /// Gets or sets the east bound lanes.
        /// </summary>
        /// <value>The east bound lanes.</value>
        public LinkedList<LinkedList<RoadUnit>> EastBoundLanes
        {
            get { return eastBoundLanes; }
            set { eastBoundLanes = value; }
        }

        /// <summary>
        /// Gets or sets the south bound lanes.
        /// </summary>
        /// <value>The south bound lanes.</value>
        public LinkedList<LinkedList<RoadUnit>> SouthBoundLanes
        {
            get { return southBoundLanes; }
            set { southBoundLanes = value; }
        }
        /// <summary>
        /// Gets or sets the north bound lanes.
        /// </summary>
        /// <value>The north bound lanes.</value>
        public LinkedList<LinkedList<RoadUnit>> NorthBoundLanes
        {
            get { return northBoundLanes; }
            set { northBoundLanes = value; }
        }
        /// <summary>
        /// Gets or sets the road units.
        /// </summary>
        /// <value>The road units.</value>
        public List<RoadUnit> RoadUnits
        {
            get { return roadUnits; }
            set { roadUnits = value; }
        }
    }


}
